<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 1. call() 方法调用一个函数，简单理解为调用函数的方式，但是它可以改变函数的 this 指向
        // 语法：函数名.call(thisArg, arg1, arg2, ...)
        // thisArg：在函数运行时指定的 this 值
        // arg1, arg2, ...：传递给函数的参数
        Function.prototype.myCall = function (context) {
            var context = context || window;
            context.fn = this;
            var args = [];
            for (var i = 1, len = arguments.length; i < arguments.length; i++) {
                args.push('arguments[' + i + ']');
            }
            var result = eval('context.fn(' + args + ')');
            delete context.fn;
            return result;
        }

        // 2. apply() 方法调用一个函数，简单理解为调用函数的方式，但是它可以改变函数的 this 指向
        // 语法：函数名.apply(thisArg, [argsArray])
        // thisArg：在函数运行时指定的 this 值
        // argsArray：一个数组或者类数组对象，其中的数组元素将作为单独的参数传给函数
        Function.prototype.myApply = function (context, arr) {
            var context = context || window;
            context.fn = this;
            var result;
            if (!arr) {
                result = context.fn();
            } else {
                var args = [];
                for (var i = 0, len = arr.length; i < len; i++) {
                    args.push('arr[' + i + ']');
                }
                result = eval('context.fn(' + args + ')');
            }
            delete context.fn;
            return result;
        }

        function foo() {
            console.log(this.name);
        }
        var obj = {
            name: '张三'
        }
        foo.myCall(obj);
        foo()
    </script>
</body>

</html>